#include <cassert>
#include <cstdio>
#include <systemc>
#include <tlm>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>

using namespace sc_core;
using namespace sc_dt;
using namespace tlm_utils;
using namespace std;

// 辅助函数：将 tlm_phase 转换为字符串
const char* phase_to_string(const tlm::tlm_phase& phase) {
    switch (phase) {
        case tlm::BEGIN_REQ:   return "BEGIN_REQ";
        case tlm::END_REQ:     return "END_REQ";
        case tlm::BEGIN_RESP:  return "BEGIN_RESP";
        case tlm::END_RESP:    return "END_RESP";
        default:               return "UNKNOWN_PHASE";
    }
}

SC_MODULE(A) {
public:
    SC_CTOR(A) {
        SC_THREAD(send);
        // 注册 nb_transport_bw 回调函数, 用于接收 Target 的 Response
        socket.register_nb_transport_bw(this, &A::nb_transport_bw);
    }
    tlm_utils::simple_initiator_socket<A> socket;

    // 用于同步
    sc_event response_event;

private:
    void send() {
        // 设置 Request Payload
        tlm::tlm_generic_payload *payload = new tlm::tlm_generic_payload();
        const char *req_data { "RequestData" };
        payload->set_data_ptr((unsigned char *) req_data);
        payload->set_data_length(strlen(req_data) + 1);  // 设置数据长度
        payload->set_command(tlm::TLM_WRITE_COMMAND);  // 设置为写命令

        sc_time delay = SC_ZERO_TIME;
        tlm::tlm_phase phase = tlm::BEGIN_REQ; // 事务阶段: 初始为 BEGIN_REQ

        // Forward Path
        printf("@%s\t[%s] FW <%s>, data=%s\n", sc_time_stamp().to_string().c_str(), this->name(), phase_to_string(phase), req_data);
        tlm::tlm_sync_enum status = socket->nb_transport_fw(*payload, phase, delay);

        // 检查同步状态(nb_transport_fw 的返回值)
        if (status == tlm::TLM_UPDATED) {
            printf("@%s\t[%s] FW <%s>\n", sc_time_stamp().to_string().c_str(), this->name(), phase_to_string(phase));
            wait(response_event);
        } else {
            SC_REPORT_ERROR("TLM", "Unexpected forward path status");
        }

        printf("@%s\t[%s] TRANS DONE\n", sc_time_stamp().to_string().c_str(), this->name());

        // 释放 payload 对象
        delete payload;
    }

    // Backward Path 回调：接收 Target 的 Response
    tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase, sc_time &delay) {
        const char *data = reinterpret_cast<const char *>(payload.get_data_ptr());
        printf("@%s\t[%s] BW <RECV RESP>, data=%s\n", sc_time_stamp().to_string().c_str(), this->name(), data);
        // 检查 TLM Phase
        if (phase == tlm::BEGIN_RESP) {
            phase = tlm::END_RESP; // 更新 Phase 为 END_RESP, 表示 Response 结束
            response_event.notify(); // 唤醒 send 线程
            return tlm::TLM_COMPLETED; // 返回 TLM_COMPLETED, 表示事务完成
        }
        return tlm::TLM_ACCEPTED;
    }
};

SC_MODULE(B) {
public:
    SC_CTOR(B) {
        // 注册 Forward Path 回调, 用于处理 Initiator 的请求
        socket.register_nb_transport_fw(this, &B::nb_transport_fw);
    }
    tlm_utils::simple_target_socket<B> socket;

private:
    // Forward Path 回调：处理 Initiator 的请求
    tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase, sc_time &delay) {
        const char *req_data = reinterpret_cast<const char *>(payload.get_data_ptr());
        printf("@%s\t[%s] FW <RECV REQ>, data=%s\n", sc_time_stamp().to_string().c_str(), this->name(), req_data);

        // 检查 TLM Phase
        if (phase != tlm::BEGIN_REQ) {
            payload.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
            return tlm::TLM_COMPLETED; // 返回 TLM_COMPLETED, 表示事务完成 (错误情况)
        }

        // 使用 sc_spawn 动态创建进程来模拟处理
        sc_spawn(sc_bind(&B::process, this, &payload));
        phase = tlm::END_REQ; // 更新阶段为 END_REQ, 表示 Request 结束

        return tlm::TLM_UPDATED; // 返回 TLM_UPDATED, 表示状态已更新
    }

    // 动态进程：模拟处理时间并发送响应 [Backward Path]
    void process(tlm::tlm_generic_payload *payload) {
        // 模拟处理时间 4ns
        wait(5, SC_NS);

        // 设置 Response Payload
        const char *resp_data { "ResponseData" };
        payload->set_data_ptr((unsigned char *) resp_data);
        payload->set_data_length(strlen(resp_data) + 1); // 设置数据长度
        payload->set_response_status(tlm::TLM_OK_RESPONSE); // 设置响应状态为 OK

        tlm::tlm_phase resp_phase = tlm::BEGIN_RESP; // 设置事务阶段: 初始为 BEGIN_RESP

        sc_time resp_delay = SC_ZERO_TIME; // 响应延迟时间

        // Backward Path
        printf("@%s\t[%s] BW <%s>, data=%s\n", sc_time_stamp().to_string().c_str(), this->name(), phase_to_string(resp_phase), resp_data);
        tlm::tlm_sync_enum status = socket->nb_transport_bw(*payload, resp_phase, resp_delay);

        // 检查同步状态(nb_transport_bw 的返回值)
        if (status == tlm::TLM_COMPLETED) {
            printf("@%s\t[%s] BW <%s>\n", sc_time_stamp().to_string().c_str(), this->name(), phase_to_string(resp_phase));
        }
        else {
            SC_REPORT_ERROR("TLM", "Unexpected backward path status");
        }
    }
};

int sc_main(int argc, char* argv[]) {
    // 实例化模块并绑定 Socket
    A a { "A" };
    B b { "B" };
    a.socket.bind(b.socket);

    // 启动仿真
    sc_start(10, SC_NS);

    return EXIT_SUCCESS;
}
